package qc.module.iot.api.channel.handler;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import qc.common.core.enums.CommunicationChannelTypeEnum;
import qc.common.core.enums.iot.IotPacketsDataFrameTypeEnum;
import qc.common.core.enums.iot.IotPacketsDataProtocolEnum;
import qc.common.core.enums.iot.IotPacketsTransmitProtocolEnum;
import qc.common.core.utils.RadixConvertUtil;
import qc.module.iot.protocol.IotFrameParseResult;
import qc.module.iot.protocol.IotPacketsSplitResult;
import qc.module.iot.service.IotChannelService;
import qc.module.iot.service.IotFramePacketsService;

import java.util.List;

/**
 * 宏电DDP传输协议通道入站Handler
 *
 * @author QuCheng Tech
 * @since 2025/11/4
 */
public class HongDianDdpTransmitChannelInboundHandler extends NettylInboundBaseHandler {
    private static final Logger logger = LoggerFactory.getLogger(HongDianDdpTransmitChannelInboundHandler.class);

    /**
     * 构造函数
     *
     * @param framePacketsService 数据帧Service
     * @param channelService      通信信道Service
     * @param packetsSendToMQ     数据帧报文是否先发送至MQ
     * @param channelId           通道ID
     * @param channelName         通道名称
     * @param channelType         通道类型
     * @param isUdp               是否使用UDP协议
     * @param port                端口
     * @param dataProtocol        数据协议
     * @return
     * @author QuCheng Tech
     * @since 2025/11/5
     */
    public HongDianDdpTransmitChannelInboundHandler(IotFramePacketsService framePacketsService, IotChannelService channelService, boolean packetsSendToMQ,
                                                    String channelId, String channelName, CommunicationChannelTypeEnum channelType,
                                                    boolean isUdp, int port, IotPacketsDataProtocolEnum dataProtocol) {
        super(framePacketsService, channelService, packetsSendToMQ, channelId, channelName, channelType,
                isUdp, port, IotPacketsTransmitProtocolEnum.DDP, dataProtocol);
    }

    //如果不需要根据传输协议进行处理可以直接使用Base中的处理方法，不需要再重载任何方法；
    //如有传输协议需要进行特殊处理，根据需要重载对应方法
    @Override
    public void channelRead(ChannelHandlerContext context, Object msg) {
        String clientIp = this.getClientIp(context);
        int clientPort = this.getClientPort(context);

        logger.debug("收到向[{}]的{}发送[{}]数据 来源客户端[{}:{}]", this.port, this.isUdp ? "UDP" : "TCP",
                this.transmitProtocol, clientIp, clientPort);

        ByteBuf readByteBuf = (ByteBuf) msg;
        try {
            int readLength = readByteBuf.readableBytes();
            //读取数据
            byte[] readBytes = new byte[readLength];
            readByteBuf.readBytes(readBytes);

            logger.info("收到向[{}]的{}发送[{}]数据 来源客户端[{}:{}]，长度[{}]，内容[{}]", this.port, this.isUdp ? "UDP" : "TCP",
                    this.transmitProtocol, clientIp, clientPort, readLength, RadixConvertUtil.toHexString(readBytes));

            //由于传输协议不是透明，需要先根据传输协议进行解析；如果根据传输协议解析出有用户数据再进行数据帧分解和解析
            List<IotPacketsSplitResult> splitTransmitPacketsResult = this.transmitFrameParse.split(readBytes);
            if (splitTransmitPacketsResult == null || splitTransmitPacketsResult.size() < 0x1) {
                //没有分解出任何可能的传输帧
                logger.info("收到报文内容[{}]中根据传输协议[{}]没有分解出任何可能的数据帧。", RadixConvertUtil.toHexString(readBytes), this.transmitProtocol);
            } else {
                //遍历分解出的可能的传输帧进行解析
                for (IotPacketsSplitResult splitTransmitPackets : splitTransmitPacketsResult) {
                    byte[] splitTransmitFrameBytes = splitTransmitPackets.getBytes();
                    try {
                        IotFrameParseResult transmitFrameParseResult = this.transmitFrameParse.parse(splitTransmitFrameBytes, false);//不解析报文正文内容
                        //IotFrameParseResult transmitFrameParseResult = this.transmitFrameParse.parse(splitTransmitFrameBytes, true);//完全解析，包含解析报文正文内容
                        if (transmitFrameParseResult.isParseSuccess() == false) {
                            logger.info("解析传输协议帧失败，报文[{}]，解析错误信息[{}]", RadixConvertUtil.toHexString(splitTransmitFrameBytes), transmitFrameParseResult.getParseErrorMsg());
                        } else {
                            logger.info("解析传输协议帧成功，帧类型[{}]，帧名称[{}]，报文[{}]，完整传输协议帧报文[{}]", transmitFrameParseResult.getFrameType(),
                                    transmitFrameParseResult.getFrameName(), RadixConvertUtil.toHexString(splitTransmitFrameBytes), RadixConvertUtil.toHexString(transmitFrameParseResult.getParseFrameBytes()));

                            try {
                                //先进行回复处理，如果生成回复报文不为空就进行回复
                                byte[] replayTransmitFrameBytes = this.transmitFrameParse.generateReplyFrame(transmitFrameParseResult);
                                if (replayTransmitFrameBytes != null && replayTransmitFrameBytes.length > 0x0) {
                                    ByteBuf responseBuf = Unpooled.wrappedBuffer(replayTransmitFrameBytes);
                                    context.writeAndFlush(responseBuf).addListener(future -> {
                                        if (future.isSuccess()) {
                                            logger.info("由[{}]的{}向客户端[{}:{}]发送[{}]回复传输协议报文成功，长度[{}]，内容[{}]", this.port, this.isUdp ? "UDP" : "TCP",
                                                    clientIp, clientPort, this.transmitProtocol, replayTransmitFrameBytes.length, RadixConvertUtil.toHexString(replayTransmitFrameBytes));
                                        } else {
                                            logger.error("由[{}]的{}向客户端[{}:{}]发送[{}]回复传输协议报文失败，长度[{}]，内容[{}]", this.port, this.isUdp ? "UDP" : "TCP",
                                                    clientIp, clientPort, this.transmitProtocol, replayTransmitFrameBytes.length, RadixConvertUtil.toHexString(replayTransmitFrameBytes));
                                        }
                                    });
                                }
                            } catch (Exception ex) {
                                logger.error("由[{}]的{}向客户端[{}:{}]进行回复传输协议报文处理时异常，异常信息[{}]", this.port, this.isUdp ? "UDP" : "TCP", clientIp, clientPort, ex.getMessage());
                            }

                            //根据包类型(解析结果对象中使用功能码属性存储包类型)进行处理：如果是注册包进行回复，如果是数据包对数据帧进行解析
                            //不需要再次根据功能码进行解析，在解析结果中如果是DTU发送用户数据时已经设置帧类型为数据，直接根据帧类型判断
                            if (transmitFrameParseResult.getFrameType() == IotPacketsDataFrameTypeEnum.DATA) {
                                //获取DDP协议解析中的用户数据字节数组，使用数据解析进行分解和解析
                                byte[] userDataBytes = transmitFrameParseResult.getBodyDataBytes();
                                List<IotPacketsSplitResult> splitDataPacketsResult = this.dataFrameParse.split(userDataBytes);
                                if (splitDataPacketsResult == null || splitDataPacketsResult.size() < 0x1) {
                                    //没有分解出任何可能的数据帧
                                    logger.info("收到报文内容[{}]中没有分解出任何可能的数据帧。", RadixConvertUtil.toHexString(userDataBytes));
                                } else {
                                    //遍历分解出的可能的数据帧进行解析
                                    for (IotPacketsSplitResult splitDataPackets : splitDataPacketsResult) {
                                        byte[] splitFrameBytes = splitDataPackets.getBytes();
                                        try {
                                            IotFrameParseResult frameParseResult = this.dataFrameParse.parse(splitFrameBytes, false);
                                            if (frameParseResult.isParseSuccess() == false) {
                                                logger.info("解析数据帧失败，报文[{}]，解析错误信息[{}]", RadixConvertUtil.toHexString(splitFrameBytes), frameParseResult.getParseErrorMsg());
                                            } else {
                                                logger.info("解析数据帧成功，帧类型[{}]，帧名称[{}]，报文[{}]，完整数据帧报文[{}]", frameParseResult.getFrameType(),
                                                        frameParseResult.getFrameName(), RadixConvertUtil.toHexString(splitFrameBytes), RadixConvertUtil.toHexString(frameParseResult.getParseFrameBytes()));

                                                //调用数据帧报文记录接口发送至MQ或保存至数据库
                                                try {
                                                    String receiveResult = framePacketsService.receive(this.channelId, this.channelName, this.channelType, this.packetsSendToMQ,
                                                            frameParseResult.getParseFrameBytes(), this.dataProtocol, frameParseResult.getFrameType(),
                                                            frameParseResult.getFrameName(), frameParseResult.getStationAddress(), frameParseResult.getDataTime());
                                                    if (StringUtils.isBlank(receiveResult)) {
                                                        //成功
                                                        logger.debug("保存数据帧时成功，报文[{}]", RadixConvertUtil.toHexString(splitFrameBytes));
                                                    } else {
                                                        //失败
                                                        logger.warn("保存数据帧失败，报文[{}]，提示信息[{}]", RadixConvertUtil.toHexString(splitFrameBytes), receiveResult);
                                                    }
                                                } catch (Exception ex) {
                                                    logger.error("保存数据帧时异常，报文[{}]，异常信息[{}]", RadixConvertUtil.toHexString(splitFrameBytes), ex.getMessage());
                                                }

                                                //解析数据帧成功后调用数据帧解析类中的生成回复方法，如果得到的回复字节数组不为空表示需要进行回复，发送对应的回复报文
                                                try {
                                                    byte[] replayFrameBytes = this.dataFrameParse.generateReplyFrame(frameParseResult);
                                                    if (replayFrameBytes != null && replayFrameBytes.length > 0x0) {
                                                        //如果有需要回复数据协议的字节数组，再使用传入协议进行打包后进行发送
                                                    }
                                                } catch (Exception ex) {
                                                    logger.error("由[{}]的{}向客户端[{}:{}]进行回复处理时异常，异常信息[{}]", this.port, this.isUdp ? "UDP" : "TCP", clientIp, clientPort, ex.getMessage());
                                                }
                                            }
                                        } catch (Exception ex) {
                                            logger.info("解析数据帧时异常，报文[{}]，异常信息[{}]", RadixConvertUtil.toHexString(splitFrameBytes), ex.getMessage());
                                        }
                                    }
                                }
                            }
                        }
                    } catch (Exception ex) {
                        logger.info("解析传输协议帧时异常，报文[{}]，异常信息[{}]", RadixConvertUtil.toHexString(splitTransmitFrameBytes), ex.getMessage());
                    }
                }
            }

            //如果通信信道中有收到报文（不管是否正确、是否有效）均判断为是一次接收到数据
            updateLatestReceivePacketsTime();
        } catch (Exception e) {
            logger.error("收到向[{}]的{}发送[{}]数据，处理收到数据时异常。来源客户端[{}:{}]，异常信息[]", this.port, this.isUdp ? "UDP" : "TCP",
                    this.transmitProtocol, clientIp, clientPort, e.getMessage());
        } finally {
            // 确保释放ByteBuf
            if (readByteBuf.refCnt() > 0) {
                readByteBuf.release();
            }
        }
    }
}